﻿using MES.Core;
using MES.Core.Filter;
using MES.Core.LoadAssemblys;
using MES.Core.Model;
using MES.Core.Utils;
using MES.Service.Generate.Dto;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;

namespace MES.Service.Generate
{
    public class GenerateService : IGenerateService
    {
        private readonly ITask _task;
        private readonly SqlSugarHelper _sqlSugarHelper;

        public GenerateService(ITask task)
        {
            _task = task;
            this._sqlSugarHelper = new SqlSugarHelper();
        }

        /// <summary>
        /// 生成Controller代码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperateResult> GenerateCode(GenerateCodeInput input)
        {
            try
            {
                var generateModeEntity = await _sqlSugarHelper.Db.Queryable<GenerateModeEntity>().Where(x => x.TableName == input.TableName).FirstAsync();
                if (generateModeEntity == null)
                {
                    return OperateResult.Fail("请先配置生成模式");
                }
                //生成Controller
                var generateControllerStringBuilder = GenerateController(input, generateModeEntity);
                var path = input.ControllerFilePath;
                var fileName = input.TableName + "Controller" + ".cs";

                //生成Service
                var generateServiceStringBuilder = GenerateServiceCS(input, generateModeEntity);
                var servicePath = input.ServiceFilePath;
                var serviceFileName = input.TableName + "Service" + ".cs";


                //生成IService
                var generateIServiceStringBuilder = GenerateIService(input, generateModeEntity);
                var IservicePath = input.ServiceFilePath;
                var IServiceFileName = input.TableName + "IService" + ".cs";
                try
                {
                    await GenerateCSFile(generateControllerStringBuilder, path, fileName);
                    await GenerateCSFile(generateServiceStringBuilder, servicePath, serviceFileName);
                    await GenerateCSFile(generateIServiceStringBuilder, IservicePath, IServiceFileName);
                    await HotLoading();

                    #region 动态注册服务
                    var assemblyLoadContext = new AssemblyLoadContext("MES.Service.LoadContext", true);
                    assemblyLoadContext.Resolving += (context, assemblyName) =>
                    {
                        // 这里可以添加逻辑来处理依赖项的解析，比如根据assemblyName去查找对应的程序集路径并加载
                        var path = GetAssemblyPath(assemblyName); // 假设你有一个方法根据名称获取程序集路径
                        if (!string.IsNullOrEmpty(path))
                        {
                            return assemblyLoadContext.LoadFromAssemblyPath(path);
                        }
                        return null;
                    };
                    var assembly = assemblyLoadContext.LoadFromAssemblyName(new AssemblyName("MES.Service"));

                    string interfaceTypeName = $"{input.ServiceNamespace}.I{input.TableName}Service";
                    string implementationTypeName = $"{input.ServiceNamespace}.{input.TableName}Service";
                    Type interfaceType = assembly.GetType(interfaceTypeName);
                    Type implementationType = assembly.GetType(implementationTypeName);
                    Type ItypeDB = typeof(IDataBaseService);
                    Type typeDB = typeof(DataBaseService);

                    if (interfaceType != null && implementationType != null && !AppSetting._Services.Any(s => s.ServiceType == interfaceType && s.ImplementationType == implementationType))
                    {
                        AppSetting.AddService(interfaceType, implementationType, ServiceLifetime.Singleton, ItypeDB, typeDB);

                    }
                    #endregion

                    return OperateResult.Success();

                }
                catch (Exception ex)
                {

                    return OperateResult.Fail(ex.Message);
                }


            }
            catch (Exception ex)
            {


                return OperateResult.Fail(ex.Message);
            }


        }

        /// <summary>
        /// 获取程序集路径
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        private string GetAssemblyPath(AssemblyName assemblyName)
        {
            string basePath = Path.Combine(AppContext.BaseDirectory, "Assemblies");
            string assemblyFileName = assemblyName.Name + ".dll";
            string fullPath = Path.Combine(basePath, assemblyFileName);
            if (File.Exists(fullPath))
            {
                return fullPath;
            }
            return null;
        }
        /// <summary>
        /// 生成IService文件
        /// </summary>
        /// <param name="input"></param>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>
        private StringBuilder GenerateIService(GenerateCodeInput input, GenerateModeEntity generateModeEntity)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine(@"using MES.Core;");
            stringBuilder.AppendLine($@"using {generateModeEntity.Namespace};");
            stringBuilder.AppendLine(@"using System.Threading.Tasks;");
            stringBuilder.AppendLine($@" namespace {input.ServiceNamespace}");
            stringBuilder.AppendLine(@"{");
            stringBuilder.AppendLine($@"    public interface I{input.TableName}Service");
            stringBuilder.AppendLine(@"    {");
            stringBuilder.AppendLine(GenerateIMethod(input, generateModeEntity));
            stringBuilder.AppendLine(@"    }");
            stringBuilder.AppendLine(@"}");
            stringBuilder.AppendLine();
            return stringBuilder;
        }

        /// <summary>
        /// 生成接口方法
        /// </summary>
        /// <param name="input"></param>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>
        private string GenerateIMethod(GenerateCodeInput input, GenerateModeEntity generateModeEntity)
        {

            var stringBuilder = new StringBuilder();
            var methods = GetMethods(generateModeEntity);
            foreach (var item in methods)
            {
                //添加接口注释
                stringBuilder.AppendLine($@"        /// <summary>");
                stringBuilder.AppendLine($@"        /// {item.Key}{generateModeEntity.TableNameComment}");
                stringBuilder.AppendLine($@"        /// </summary>");
                stringBuilder.AppendLine($@"        /// <param name=""input""></param>");
                stringBuilder.AppendLine($@"        Task<OperateResult> {item.Value}({input.TableName} input);");
                stringBuilder.AppendLine();
                stringBuilder.AppendLine();
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// 生成接口实现方法
        /// </summary>
        /// <param name="input"></param>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>
        private string GenerateServiceMethod(GenerateCodeInput input, GenerateModeEntity generateModeEntity)
        {
            var stringBuilder = new StringBuilder();
            var methods = GetMethods(generateModeEntity);
            //添加构造函数
            stringBuilder.AppendLine($@"    private readonly IDataBaseService _dataBaseService;");
            stringBuilder.AppendLine($@"        public {input.TableName}Service(IDataBaseService dataBaseService)");
            stringBuilder.AppendLine("        {");
            stringBuilder.AppendLine("            _dataBaseService = dataBaseService;");
            stringBuilder.AppendLine("        }");

            foreach (var method in methods)
            {
                stringBuilder.AppendLine($@"        /// <summary>");
                stringBuilder.AppendLine($@"        /// {method.Key}{generateModeEntity.TableNameComment}");
                stringBuilder.AppendLine($@"        /// </summary>");
                stringBuilder.AppendLine($@"        /// <param name=""input""></param>");
                stringBuilder.AppendLine($@"         public async  Task<OperateResult> {method.Value}({input.TableName} input){{");
                stringBuilder.AppendLine($@"            {SwitchMethod(method.Key, input)}");
                stringBuilder.AppendLine($@"            return res > 0 ? OperateResult.Success(""添加成功"") : OperateResult.Fail(""添加失败"");");
                stringBuilder.AppendLine("        }");
                stringBuilder.AppendLine();
                stringBuilder.AppendLine();
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// 筛选使用的数据库操作方法
        /// </summary>
        /// <param name="methodKey"></param>
        /// <returns></returns>
        private string SwitchMethod(string methodKey, GenerateCodeInput input)
        {
            switch (methodKey)
            {
                case "新增":
                    return $"var res = await _dataBaseService.sqlSugarClient.Insertable<{input.TableName}>(input).ExecuteCommandAsync();";
                case "修改":
                    return $"var res = await _dataBaseService.sqlSugarClient.Updateable<{input.TableName}>(input).ExecuteCommandAsync();";
                case "删除":
                    return $"var res = await _dataBaseService.sqlSugarClient.Deleteable<{input.TableName}>(input).ExecuteCommandAsync();";
                default:
                    return "";
            }
        }

        /// <summary>
        /// 生成Service文件
        /// </summary>
        /// <param name="input"></param>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>
        private StringBuilder GenerateServiceCS(GenerateCodeInput input, GenerateModeEntity generateModeEntity)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine(@"using MES.Core;");
            stringBuilder.AppendLine($@"using {generateModeEntity.Namespace};");
            stringBuilder.AppendLine($@" namespace {input.ServiceNamespace}");
            stringBuilder.AppendLine(@"{");
            stringBuilder.AppendLine($@"    public class {input.TableName}Service:I{input.TableName}Service");
            stringBuilder.AppendLine(@"    {");
            stringBuilder.AppendLine(GenerateServiceMethod(input, generateModeEntity));
            stringBuilder.AppendLine(@"    }");
            stringBuilder.AppendLine(@"}");
            stringBuilder.AppendLine();
            return stringBuilder;
        }

        /// <summary>
        /// 生成模型
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<OperateResult> GenerateModel(GenerateModelInput input)
        {
            try
            {
                StringBuilder stringBuilder = GenerateEntity(input);

                var path = input.FilePath;
                var fileName = input.TableName + ".cs";
                await GenerateCSFile(stringBuilder, path, fileName);
                GenerateModeEntity generateModeEntity = new GenerateModeEntity();
                var result = await _sqlSugarHelper.Db.Queryable<GenerateModeEntity>().Where(x => x.TableName == input.TableName).FirstAsync();
                if (result != null)
                {
                    generateModeEntity.Id = result.Id;
                }
                //插入数据库

                generateModeEntity.TableNameComment = input.TableNameComment;
                generateModeEntity.TableName = input.TableName;
                generateModeEntity.FilePath = input.FilePath;
                generateModeEntity.Namespace = input.Namespace;
                await _sqlSugarHelper.Db.Storageable(generateModeEntity).DefaultAddElseUpdate().ExecuteCommandAsync();//插入或者修改数据库
                await HotLoading();
                return OperateResult.Success();
            }
            catch (Exception ex)
            {

                return OperateResult.Fail(ex.Message);
            }

        }

        /// <summary>
        /// 生成Cs文件
        /// </summary>
        /// <param name="stringBuilder"></param>
        /// <param name="path"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private async Task GenerateCSFile(StringBuilder stringBuilder, string path, string fileName)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            using (FileStream stream = new FileStream(Path.Combine(path, fileName), FileMode.Create))
            {
                await stream.WriteAsync(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
            }

        }

        /// <summary>
        /// 重新启动程序集
        /// </summary>
        /// <returns></returns>
        public Task<OperateResult> HotLoading()
        {
            try
            {
                _task.Run();
                return Task.FromResult(OperateResult.Success());
            }
            catch (Exception ex)
            {
                return Task.FromResult(OperateResult.Fail(ex.Message));
            }

        }



        /// <summary>
        ///  生成Controller
        /// </summary>
        /// <param name="input"></param>
        /// <param name="generateModeEntity"></param>
        private StringBuilder GenerateController(GenerateCodeInput input, GenerateModeEntity generateModeEntity)
        {
            var stringBuilder = new StringBuilder();
            stringBuilder.AppendLine(@"using MES.Core;");
            stringBuilder.AppendLine($@"using {generateModeEntity.Namespace};");
            stringBuilder.AppendLine($@"using {input.ServiceNamespace};");
            stringBuilder.AppendLine($@" using Microsoft.AspNetCore.Mvc;");
            stringBuilder.AppendLine($@" namespace {input.ControllerNamespace}");
            stringBuilder.AppendLine("{");
            string prefix = "\t";

            stringBuilder.AppendLine($"{prefix}/// <summary>");
            stringBuilder.AppendLine($"{prefix}///{generateModeEntity.TableNameComment}服务管理");
            stringBuilder.AppendLine($"{prefix}/// </summary>");

            stringBuilder.AppendLine($@" {prefix}[Route(""api/[controller]/[Action]"")]");
            stringBuilder.AppendLine($@" {prefix}[ApiVersion(""{input.ApiVersionNo}"", Deprecated = false)]");
            stringBuilder.AppendLine($@" {prefix}[ApiController]");

            stringBuilder.AppendLine($@" {prefix}public class {input.TableName}Controller : ControllerBase");
            stringBuilder.AppendLine($"{prefix}{{");
            string filedPrefix = "\t\t";
            stringBuilder.AppendLine($@" {filedPrefix} private readonly I{input.TableName}Service _{input.TableName.FirstCharToLower()}Service;");
            stringBuilder.AppendLine($@" {filedPrefix} public {input.TableName}Controller(I{input.TableName}Service {input.TableName.FirstCharToLower()}Service)");
            stringBuilder.AppendLine($"{filedPrefix}{{");
            string threePrefix = "\t\t\t";
            stringBuilder.AppendLine($"{threePrefix}this._{input.TableName.FirstCharToLower()}Service = {input.TableName.FirstCharToLower()}Service;");
            stringBuilder.AppendLine($"{filedPrefix}}}");
            stringBuilder.AppendLine(GenerateControllerMethod(generateModeEntity));
            return stringBuilder;
        }

        /// <summary>
        /// 生成接口方法
        /// </summary>
        private string GenerateControllerMethod(GenerateModeEntity generateModeEntity)
        {
            var controllerMethods = GetControllerMethods(generateModeEntity);
            var methods = GetMethods(generateModeEntity);
            var stringBuilder = new StringBuilder();
            foreach (var controllerMethod in controllerMethods)
            {
                string prefix = "\t";
                var methodsValue = methods[controllerMethod.Key];
                stringBuilder.AppendLine();
                stringBuilder.AppendLine();
                stringBuilder.AppendLine($"     {prefix}/// <summary>");
                stringBuilder.AppendLine($"     {prefix}/// {controllerMethod.Key}{generateModeEntity.TableName}");
                stringBuilder.AppendLine($"     {prefix}/// </summary>");
                stringBuilder.AppendLine($@"    {prefix}/// <param name=""input""></param>");
                stringBuilder.AppendLine($@"     {prefix}/// <returns></returns>");
                stringBuilder.AppendLine($@"     {prefix}[{controllerMethod.Value}]");
                stringBuilder.AppendLine($@"   {prefix}public async Task<OperateResult> {methodsValue}([FromBody] {generateModeEntity.TableName} input)");
                stringBuilder.AppendLine($"{prefix}{{");

                var _service = $"this._{generateModeEntity.TableName.FirstCharToLower()}Service";
                stringBuilder.AppendLine($@"     {prefix}return await {_service}.{methodsValue}(input);");
                stringBuilder.AppendLine($"{prefix}}}");

                stringBuilder.AppendLine();
                stringBuilder.AppendLine();
            }
            stringBuilder.AppendLine("}");
            stringBuilder.AppendLine("}");
            return stringBuilder.ToString();
        }

        /// <summary>
        /// 接口层使用的接口名称与请求方式
        /// </summary>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>

        private Dictionary<string, string> GetControllerMethods(GenerateModeEntity generateModeEntity)
        {
            var dic = new Dictionary<string, string>();
            dic.Add("新增", $"HttpPost");
            dic.Add("删除", $"HttpDelete");
            dic.Add("修改", $"HttpPut");
            return dic;
        }

        /// <summary>
        /// 要生成的方法
        /// </summary>
        /// <param name="generateModeEntity"></param>
        /// <returns></returns>
        private Dictionary<string, string> GetMethods(GenerateModeEntity generateModeEntity)
        {

            var dic = new Dictionary<string, string>();
            dic.Add("新增", $"Add{generateModeEntity.TableName}Async");
            dic.Add("删除", $"Delete{generateModeEntity.TableName}Async");
            dic.Add("修改", $"Update{generateModeEntity.TableName}Async");

            return dic;

        }

        /// <summary>
        /// 生成实体
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private StringBuilder GenerateEntity(GenerateModelInput input)
        {
            var stringBuilder = new StringBuilder();

            stringBuilder.AppendLine("using System;");
            stringBuilder.AppendLine("using System.Data;");
            stringBuilder.AppendLine("using SqlSugar;");
            stringBuilder.AppendLine($"namespace {input.Namespace}");//命名空间
            stringBuilder.AppendLine("{");
            string prefix = "\t";

            stringBuilder.AppendLine($"{prefix}/// <summary>");
            stringBuilder.AppendLine($"{prefix}///{input.TableNameComment}");//表注释
            stringBuilder.AppendLine($"{prefix}/// </summary>");
            stringBuilder.AppendLine($@"      [SugarTable(""{input.TableName}"")]");
            stringBuilder.AppendLine($"{prefix}public class {input.TableName}: ModelBase");//表名
            stringBuilder.AppendLine($"{prefix}{{");
            string filedPrefix = "\t\t";
            //默认在当前可执行目录下生成实体
            foreach (var item in input.GenerateKeys)
            {
                //添加注释
                stringBuilder.AppendLine($"{filedPrefix}/// <summary>");
                stringBuilder.AppendLine($"{filedPrefix}///{item.KeyComment}");//字段注释
                stringBuilder.AppendLine($"{filedPrefix}/// </summary>");
                string dataType = GetCLRType(item.KeyType);
                //添加字段声明
                stringBuilder.AppendLine($@"        [SugarColumn(ColumnDescription = ""{item.KeyComment}"",Length ={item.KeyLength})] ");
                stringBuilder.AppendLine($"{filedPrefix}public {dataType} {item.KeyName}  {{ get; set; }} ");
            }
            stringBuilder.AppendLine($"{prefix}}}");
            stringBuilder.AppendLine($"}}");
            return stringBuilder;
        }


        /// <summary>
        /// 根据数据库类型获取字段类型
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        private string GetCLRType(string dbType)
        {
            switch (dbType)
            {
                case "tinyint":
                case "smallint":
                case "mediumint":
                case "int":
                case "integer":
                    return "int";
                case "bigint":
                    return "long";
                case "double":
                    return "double";
                case "float":
                    return "float";
                case "decimal":
                    return "decimal";
                case "numeric":
                case "real":
                    return "decimal";
                case "bit":
                    return "bool";
                case "date":
                case "time":
                case "year":
                case "datetime":
                case "timestamp":
                    return "DateTime";
                case "tinyblob":
                case "blob":
                case "mediumblob":
                case "longblog":
                case "binary":
                case "varbinary":
                    return "byte[]";
                case "char":
                case "varchar":
                case "tinytext":
                case "text":
                case "mediumtext":
                case "longtext":
                    return "string";
                case "point":
                case "linestring":
                case "polygon":
                case "geometry":
                case "multipoint":
                case "multilinestring":
                case "multipolygon":
                case "geometrycollection":
                case "enum":
                case "set":
                default:
                    return dbType;
            }
        }
    }
}
